<template>
  <div class="flex flex-col bg-[#edf5fe] h-screen box-border">
    <div v-if="isMac() && isElectron()" class="mac-titlebar"></div>
    <img
      src="@/icons/svg/badge/badge_bg.svg"
      alt="bg"
      class="absolute top-0 left-0 w-full z-[1]"
    />
    <van-pull-refresh
      v-model="isLoading"
      success-text="刷新成功"
      style="min-height: 100vh"
      class="z-[10]"
      @refresh="onRefresh(true)"
    >
      <div class="flex flex-col h-full z-[10] pt-10">
        <div
          v-if="!isElectron()"
          class="flex flex-row justify-between items-center px-4 py-4"
        >
          <van-icon name="arrow-left" size="24" @click="exitRoomByNative" />
          <h3 class="text-[18px] font-bold text-black"></h3>
          <div class="w-6"></div>
        </div>
        <RecordView :is-recording="isRecording" :time="formattedDuration" />

        <div class="flex flex-col gap-4 bg-white rounded-t-[24px] flex-auto pt-5">
          <div class="flex flex-col flex-auto px-5">
            <DeviceInfoView
              class="mb-5"
              v-if="cp_deviceInfo"
              :deviceInfo="cp_deviceInfo"
            />

            <div class="px-5 py-5 bg-[#F9FAFC] text-[14px] rounded-lg">
              <h5 class="text-[14px] font-bold text-black">温馨提示</h5>
              <ul class="mt-2 text-[#757575]">
                <li class="flex items-start gap-2">
                  <span>1.</span>
                  录制期间请保持工牌电量充足，建议提前充满电，避免录制中因低电量自动关机。
                </li>
              </ul>
              <ul class="mt-1 text-[#757575]">
                <li class="flex items-start gap-2">
                  <span>2.</span>
                  与客户沟通结束后，请在当前页面点击 【结束】按钮。
                </li>
              </ul>
            </div>
          </div>

          <div
            :class="`${
              isElectron() ? 'pb-4' : 'pb-8'
            } w-full flex gap-4 px-4 flex-row justify-between items-center box-border pt-4 relative`"
          >
            <div class="absolute top-0 left-0 right-0 h-[0.5px] bg-[#e9e9e9b1]"></div>
            <div class="w-full h-[40px]">
              <van-button
                plain
                color="red"
                size="large"
                @click="() => debounce(() => clickExit())"
                >结束</van-button
              >
            </div>
            <div class="w-full h-[40px]">
              <van-button
                color="#436BFF"
                size="large"
                :loading="btnLoading"
                @click="() => clickPauseAndContinue()"
                >{{ isRecording ? "暂停" : "继续" }}</van-button
              >
            </div>
          </div>
        </div>
      </div>
    </van-pull-refresh>
  </div>
</template>

<script setup lang="ts">
import { useRoute, useRouter } from "vue-router";
import dayjs from "dayjs";
import { onMounted, onUnmounted, ref, computed } from "vue";
import {
  controlRecordAPI,
  endLiveConferenceAPI,
  getRecordingAPI,
} from "@/services/badge";
import {
  CMD_TYPE,
  ControlRecord,
  OnGoingVisit,
  RECORD_STATUS,
  RECORD_TYPE,
} from "@/services/badge/type";
import debounce from "@/utils/debounce";
import { yxtShowLoading } from "@/utils/yxtToast";
import { closeToast, showConfirmDialog, showDialog, showToast } from "vant";
import {
  RECORDING_CODE,
  RECORDING_CODE_LIVE,
  SUCCESS_CODE,
} from "@/services/apiErrorCode";
import "vant/lib/index.css";
import { useWebSocket } from "@vueuse/core";
import { getToken, getUserInfo } from "@/utils/auth";
import { getPlatform, isElectron, isMac } from "@/utils/platformTool";
import { SocketEventType } from "@/services/socketEvent";
import RecordView from "./components/recordView.vue";
import DeviceInfoView from "./components/deviceInfo.vue";
import { useDeviceInfo } from "@/composables/useDeviceInfo";
import { useRecordTime } from "@/composables/useRecorddTime";
import { useBreadcrumb } from "@/composables/useBreadcrumb";
import { loadInfoFromPC, closeWindow } from "@/utils/electronTool";

const route = useRoute();
const router = useRouter();
const scheduleId = ref(route.query.scheduleId?.toString() || "");
const fromContinue = ref((route.query.continue || "") === "true");
const startTime = ref();
const visitId = ref("");

// 使用面包屑管理composable
const {
  addBreadcrumb,
  addSystemBreadcrumb,
  addErrorBreadcrumb,
  reportBreadcrumbs,
  setupPageLifecycle,
} = useBreadcrumb();

const { deviceInfo, startPolling, reloadDeviceInfo } = useDeviceInfo({
  // 开启电量检测
  enableBatteryCheck: true,
  // 当电量低于 20 ， 5 弹出提示
  thresholds: [20, 5],
});

const {
  formattedDuration,
  start: startRecordTime,
  pause: pauseRecordTime,
  resume: resumeRecordTime,
  setStartTime,
  setDuration,
} = useRecordTime();

let cleanupPageLifecycle: (() => void) | null = null;

onMounted(async () => {
  // 设置页面生命周期管理
  cleanupPageLifecycle = setupPageLifecycle("badge_record", {
    scheduleId: scheduleId.value,
    fromContinue: fromContinue.value,
  });

  addBreadcrumb("当前时间:", new Date().toISOString());

  if (isElectron()) {
    loadInfoFromPC(() => checkRecordStatus());
  } else {
    checkRecordStatus();
  }
});

// 在组件卸载时清理
onUnmounted(() => {
  addSystemBreadcrumb("组件即将卸载");

  // 清理页面生命周期监听器
  if (cleanupPageLifecycle) {
    cleanupPageLifecycle();
  }

  // 组件卸载时上报面包屑
  let name = getUserInfo().name;
  reportBreadcrumbs(`工牌页面退出, ${name}, ${isFirst.value ? "首次" : ""}`);

  if (timer.value) {
    cancelAnimationFrame(timer.value);
  }
  // 清理 WebSocket 连接
  if (ws) {
    const { close } = ws;
    close();
  }
});

const cp_deviceInfo = computed(() => {
  return deviceInfo.value;
});

let ws: any = null;

const reconnectAttempts = ref(0);

function initWebSocket() {
  let token = getToken();
  if (!token || token.length === 0) {
    console.warn("token 为空，不进行websocket连接");
    addSystemBreadcrumb("token为空，跳过WebSocket连接");
    return;
  }

  const socketUrl = import.meta.env.VITE_XMATE_SOCKET_URL;
  let url = `${socketUrl}?token=${token}&clientType=${getPlatform()}`;

  addSystemBreadcrumb("开始建立WebSocket连接");

  ws = useWebSocket(url, {
    autoReconnect: {
      delay: 3000,
      onFailed() {
        addErrorBreadcrumb("WebSocket连接失败");
        showToast("WebSocket连接失败");
      },
    },
    onConnected(ws) {
      console.log("Connected", ws);
      addSystemBreadcrumb("WebSocket连接成功");
      reconnectAttempts.value = 0;
    },
    onDisconnected(ws: WebSocket, event: CloseEvent) {
      console.log("Disconnected", event);
      addSystemBreadcrumb("WebSocket连接断开，原因:", event.reason || "未知");
      reconnectAttempts.value++;

      // 如果断开次数过多，上报面包屑
      if (reconnectAttempts.value >= 3) {
      }
    },
    onError(ws: WebSocket, event: Event) {
      console.error("Error", event);
      addErrorBreadcrumb("WebSocket连接出现错误");
      // WebSocket错误时上报面包屑
    },
    onMessage(ws: WebSocket, event: MessageEvent) {
      try {
        const data = JSON.parse(event.data);
        addSystemBreadcrumb("收到WebSocket消息:", data.endpoint);
        onEvent({ data: event.data });
      } catch (error) {
        console.error("WebSocket消息解析错误:", error);
        addErrorBreadcrumb("WebSocket消息解析错误:", error);
        // 消息解析错误时上报面包屑
      }
    },
  });
}

const timer = ref<number | null>(null);

function onEvent(event: any) {
  addBreadcrumb("onEvent", event);
  let { data } = event;
  data = JSON.parse(data);
  const { endpoint: eventType } = data;

  if (eventType === SocketEventType.XMATE_DEVICE_BATTERY_LOW_RECORD_STOP) {
    addSystemBreadcrumb("设备电量不足，自动停止录制");
    deviceStopRecord("电量不足");
  }
  if (eventType === SocketEventType.XMATE_DEVICE_RECORD_STOP) {
    addSystemBreadcrumb("另一端结束录制");
    deviceStopRecord("另一端结束本次沟通");
  }
  if (eventType === SocketEventType.XMATE_DEVICE_RECORD_STATUS_CHANGE) {
    addSystemBreadcrumb("设备录制状态发生变化");
    onRefresh();
  }
}

const haveLeave = ref(false);
function showEndRoomFailure(msg: string) {
  haveLeave.value = false;
  addBreadcrumb("显示结束房间失败对话框:", msg);

  showConfirmDialog({
    title: "结束沟通失败",
    message: msg,
    confirmButtonText: "直接离开",
    cancelButtonText: "再试一次",
  })
    .then(() => {
      addBreadcrumb("用户选择直接离开");
      exitRoom();
    })
    .catch(() => {
      console.log("catch: ", haveLeave.value);
      addBreadcrumb("用户选择再试一次");
      if (!haveLeave.value) {
        endRecord();
      }
    });
}

function showStartRoomFailure(msg: string) {
  haveLeave.value = false;
  addBreadcrumb("显示启动房间失败对话框:", msg);

  // 启动房间失败时上报面包屑

  showConfirmDialog({
    title: "启动工牌失败",
    message: msg,
    confirmButtonText: "直接离开",
    cancelButtonText: "再试一次",
  })
    .then(() => {
      addBreadcrumb("用户选择直接离开");
      exitRoom();
    })
    .catch(() => {
      console.log("catchStart failure: ", haveLeave.value);
      addBreadcrumb("用户选择再试一次");
      if (!haveLeave.value) {
        startRecord();
      }
    });
}

function showMsgAlert(message: string) {
  addBreadcrumb("showMsgAlert 遇到点问题:", message);
  showDialog({
    title: `遇到点问题`,
    message: message,
    confirmButtonText: "知道了",
  }).then(() => {
    // exitRoomByNative();
  });
}

const isFirst = ref(true);
function showRecordingAlert(onGoingVisit: OnGoingVisit | null = null) {
  let enableContinue = onGoingVisit && onGoingVisit.startTime.length > 0;

  showConfirmDialog({
    title: "您有沟通正在进行中",
    message: "如想【开启新的沟通】，请先【结束】正在进行的沟通",
    confirmButtonText: "结束",
    cancelButtonText: enableContinue ? "继续" : "离开",
  })
    .then(() => {
      restartRecord();
    })
    .catch(() => {
      if (enableContinue) {
        console.log("enableContinue onGoingVisit", onGoingVisit);

        handleStartSuccess(
          onGoingVisit?.startTime,
          onGoingVisit?.duration,
          onGoingVisit?.recordStatus === RECORD_STATUS.PAUSED
        );
      } else {
        exitRoom();
      }
    });
}

// 有LiveKit类型的会议正在录制
function showLiveKitRecordingAlert(data: any) {
  const { conferenceId, subject, hostUserId } = data;

  showConfirmDialog({
    title: "您有沟通正在进行中",
    message: `沟通主题: ${subject}\n如想开启新的沟通，请先结束正在进行的沟通`,
    confirmButtonText: "结束",
    cancelButtonText: "暂不",
  })
    .then(() => {
      stopLiveRecordAndStart(conferenceId, hostUserId);
    })
    .catch(() => {
      // 暂不
      exitRoom();
    });
}

async function restartRecord() {
  yxtShowLoading({ duration: 0, message: "正在结束上一次录制", overlay: true });
  const parameters = new ControlRecord(CMD_TYPE.STOP);
  const res = await doAPI(() => controlRecordAPI(parameters));
  const { message } = res;
  if (res.code !== SUCCESS_CODE) {
    // 弹出一个确认框
    // 给用户选择，再试一次，还是直接退出
    closeToast();
    showEndRoomFailure(message);
    return;
  }

  await startRecord();
}

async function stopLiveRecordAndStart(lastConferenceId: string, hostUserId: string) {
  // 调用结束上一次的会议id
  yxtShowLoading({ duration: 0, message: "正在结束上一次录制", overlay: true });
  const res = await doAPI(() => endLiveConferenceAPI(lastConferenceId, hostUserId));
  const { message } = res;
  if (res.code !== SUCCESS_CODE) {
    // 弹出一个确认框
    // 给用户选择，再试一次，还是直接退出
    closeToast();
    showToast(message);
    setTimeout(() => exitRoom(), 1500);
    return;
  }
  yxtShowLoading({ duration: 0, message: "正在重新启动录制", overlay: true });
  await startRecord();
  closeToast();
}

const btnLoading = ref(false);
async function clickExit() {
  try {
    addBreadcrumb("用户点击结束录制按钮");

    showConfirmDialog({
      title: "确认要结束录制吗",
      confirmButtonText: "确认",
      cancelButtonText: "取消",
    })
      .then(() => {
        addBreadcrumb("用户确认结束录制");
        endRecord();
      })
      .catch(() => {
        addBreadcrumb("用户取消结束录制");
        // 用户取消时也上报面包屑，记录用户行为
      });
  } catch (error) {
    console.error("Failed to clickExit:", error);
  }
}

const allowControlRecord = ref(true);
async function clickPauseAndContinue() {
  if (!allowControlRecord.value) {
    showToast("请不要频繁操作, 5s后再试");
    return;
  }
  btnLoading.value = true;

  const action = isRecording.value ? "暂停录制" : "继续录制";
  addBreadcrumb(`用户点击${action}按钮`);

  if (isRecording.value) {
    await pauseRecord();
  } else {
    await continueRecord();
  }
  allowControlRecord.value = false;
  setTimeout(() => {
    allowControlRecord.value = true;
  }, 5000);
  btnLoading.value = false;
}

const isRecording = ref(false);
async function checkRecordStatus() {
  addBreadcrumb("开始检查录制状态");
  yxtShowLoading({ message: "正在检查录制状态", overlay: true, duration: 0 });
  const data: OnGoingVisit = await doAPI(() => getRecordingAPI());
  closeToast();

  // 存在录制
  let tempRecording = data.conferenceId?.length > 0;
  let isBadge = data.recordType === RECORD_TYPE.DEVICE;

  addBreadcrumb(`录制状态检查完成 - 有录制: ${tempRecording}, 是工牌: ${isBadge}`);

  if (tempRecording && isBadge) {
    isFirst.value = false;
    if (fromContinue.value) {
      let isPause = data.recordStatus === RECORD_STATUS.PAUSED;
      addBreadcrumb(`从继续页面进入，录制状态: ${isPause ? "暂停" : "录制中"}`);
      handleStartSuccess(data.startTime, data.duration, isPause);
      return;
    }
    // 恢复录制
    addBreadcrumb("发现正在进行的录制，显示录制提示");
    showRecordingAlert(data);
  } else {
    addBreadcrumb("没有正在进行的录制，开始新录制");
    startRecord();
  }
}

// 开启录制
async function startRecord() {
  addBreadcrumb("开始启动录制");

  const parameters = new ControlRecord(CMD_TYPE.START, scheduleId.value);
  yxtShowLoading({ duration: 0, message: "正在启动录制", overlay: true });

  const res = await doAPI(() => controlRecordAPI(parameters));
  closeToast();

  const { message, data } = res;

  if (res.code === RECORDING_CODE) {
    // 设备正在录制中
    addBreadcrumb("设备正在录制中，显示录制提示");
    showRecordingAlert();
    return;
  }
  if (res.code === RECORDING_CODE_LIVE) {
    // 设备正在录制中
    addBreadcrumb("发现LiveKit录制正在进行");
    showLiveKitRecordingAlert(data);
    return;
  }

  if (res.code !== SUCCESS_CODE) {
    addBreadcrumb(`启动录制失败: ${message}`);
    showStartRoomFailure(message);
    return;
  }

  visitId.value = data;
  addBreadcrumb(`录制启动成功，访问ID: ${data}`);
  handleStartSuccess().then();
  closeToast();
}

// 结束录制
async function endRecord() {
  addBreadcrumb("开始执行结束录制操作");

  const parameters = new ControlRecord(CMD_TYPE.STOP);
  yxtShowLoading({ duration: 0, message: "正在结束录制", overlay: true });
  const res = await doAPI(() => controlRecordAPI(parameters));
  const { message } = res;
  if (res.code !== SUCCESS_CODE) {
    // 弹出一个确认框
    // 给用户选择，再试一次，还是直接退出
    closeToast();
    addBreadcrumb("结束录制失败:", message);
    showEndRoomFailure(message);
    return;
  }
  closeToast();
  pauseRecordTime();
  addBreadcrumb("录制结束成功，准备退出");
  exitRoom();
}

// 暂停录制
async function pauseRecord() {
  addBreadcrumb("开始暂停录制");
  reloadDeviceInfo().then();
  const parameters = new ControlRecord(CMD_TYPE.PAUSE);
  yxtShowLoading({ duration: 0, message: "正在暂停录制", overlay: true });
  const res = await doAPI(() => controlRecordAPI(parameters));
  const { message, code } = res;
  if (code !== SUCCESS_CODE) {
    closeToast();
    addBreadcrumb(`暂停录制失败: ${message}`);
    showMsgAlert(message);
    return;
  }
  isRecording.value = false;
  closeToast();
  addBreadcrumb("录制暂停成功");
  pauseRecordTime();
}

// 记录录制
async function continueRecord() {
  addBreadcrumb("开始继续录制");
  reloadDeviceInfo().then();
  const parameters = new ControlRecord(CMD_TYPE.RESUME);
  yxtShowLoading({ duration: 0, message: "正在继续录制", overlay: true });
  const res = await doAPI(() => controlRecordAPI(parameters));
  const { message, code } = res;
  if (code !== SUCCESS_CODE) {
    closeToast();
    addBreadcrumb(`继续录制失败: ${message}`);
    showMsgAlert(message);
    pauseRecordTime();
    return;
  }
  isRecording.value = true;
  closeToast();
  addBreadcrumb("录制继续成功");
  resumeRecordTime();
}

// 处理开始录制成功 [开始/继续]
async function handleStartSuccess(
  timeStr: string = "",
  duration: number = 0,
  isPause: boolean = false
) {
  console.log("handleStartSuccess：", timeStr, duration, isPause);
  let name = getUserInfo().name;
  reportBreadcrumbs(`工牌页面开始录制, ${name}, ${isFirst.value ? "首次" : ""}`);
  addBreadcrumb(
    "处理录制成功",
    "持续时间:",
    duration,
    "秒, 是否暂停:",
    isPause,
    "开始时间:",
    timeStr
  );

  setTimeout(() => {
    initWebSocket();
  }, 2100);

  startTime.value = dayjs();

  isRecording.value = !isPause;

  startPolling();
  setStartTime(startTime.value);
  setDuration(duration);
  startRecordTime();
  if (isPause) {
    pauseRecordTime();
    await continueRecord();
  }
}

const showStopAlert = ref(false);
function deviceStopRecord(reason: string) {
  if (showStopAlert.value) return;
  let time = dayjs().format("HH:mm:ss");
  showStopAlert.value = true;
  addBreadcrumb("设备停止录制", "时间:", time, "原因:", reason);
  showDialog({
    title: `您的工牌录制功能已于${time}停止`,
    message: reason,
    confirmButtonText: "知道了",
  }).then(() => {
    showStopAlert.value = false;
    exitRoom();
  });
}

function exitRoom() {
  console.log("exitRoom");
  haveLeave.value = true;
  addBreadcrumb("执行退出房间操作");

  setTimeout(() => {
    console.log("push");
    router.push({ path: "/badge" });
  }, 1000);
  exitRoomByNative();
}

function exitRoomByNative() {
  addBreadcrumb("退出录制页面 by flutter");
  let name = getUserInfo().name;
  reportBreadcrumbs(`工牌页面退出, ${name}, ${isFirst.value ? "首次" : ""}`);

  if (isElectron()) {
    closeWindow();
  } else {
    window.flutter_inappwebview.callHandler("exitRoom");
  }
}

const isLoading = ref(false);
async function onRefresh(needLoading: boolean = false) {
  addBreadcrumb("开始刷新页面数据");

  if (needLoading) {
    isLoading.value = true;
  }

  const data: OnGoingVisit = await doAPI(() => getRecordingAPI());
  reloadPage(data);
  await reloadDeviceInfo();
  isLoading.value = false;

  addBreadcrumb("页面数据刷新完成");
}

async function reloadPage(onGoingVisit: OnGoingVisit) {
  const isPaused = onGoingVisit.recordStatus === RECORD_STATUS.PAUSED;
  addBreadcrumb(
    "重新加载页面状态",
    "是否暂停:",
    isPaused,
    "持续时间:",
    onGoingVisit.duration,
    "录制状态:",
    onGoingVisit.recordStatus
  );

  isRecording.value = !isPaused;
  setDuration(onGoingVisit.duration);
  if (isPaused) {
    pauseRecordTime();
  } else {
    resumeRecordTime();
  }
}

async function doAPI(fn: Function) {
  try {
    // 延迟61秒
    return await fn();
  } catch (e) {
    closeToast();
    addErrorBreadcrumb("API调用失败:", e);
    showMsgAlert(`${e}`);
  }
}
</script>

<style scoped lang="less">
.safe-area-top {
  padding-top: constant(safe-area-inset-top);
  padding-top: env(safe-area-inset-top);
}

.mac-titlebar {
  -webkit-app-region: drag;
  height: 40px;
  display: flex;
  font-weight: 500;
  justify-content: center;
  align-items: center;
  top: 0;
  width: 100%;
  z-index: 10;
  position: absolute;
}

div {
  --van-button-large-height: 40px;
}
</style>
